﻿using System.Collections.Generic;
using AutoMapper;
using Lucid.ESA.ClientDataSystem.Application.Contracts;
using Lucid.ESA.ClientDataSystem.Application.DataTransferObjects;
using Lucid.ESA.ClientDataSystem.Application.Requests;
using Lucid.ESA.ClientDataSystem.Application.Responses;
using Lucid.ESA.ClientDataSystem.Data.Common;
using Lucid.ESA.ClientDataSystem.Domain.Common;
using Lucid.ESA.ClientDataSystem.Domain.Entities;
using Lucid.ESA.ClientDataSystem.Domain.ParameterClasses;
using Lucid.ESA.ClientDataSystem.Domain.RepositoryContracts;
using StructureMap;

namespace Lucid.ESA.ClientDataSystem.Application.Implementations
{
    public class SiteService : ISiteService
    {
        public Response GetSiteById(long id)
        {
            //Load required repositories.
            ISiteRepository siteRepository = ObjectFactory.GetInstance<ISiteRepository>();

            //Get the entity.
            Site site = siteRepository.GetById(id);

            //Map to DTO.
            Mapper.Reset();
            Mapper.CreateMap<Site, SiteDto>();
            Mapper.CreateMap<Client, ClientDto>()
                .ForMember(prop => prop.Sites, opt => opt.Ignore())
                .ForMember(prop => prop.Contacts, opt => opt.Ignore());
            SiteDto siteDto = Mapper.Map<Site, SiteDto>(site);

            //Return DTO in a response object.
            return new GetResponse<SiteDto>(siteDto);
        }

        public Response GetAllSites()
        {
            //Load required repositories.
            ISiteRepository siteRepository = ObjectFactory.GetInstance<ISiteRepository>();

            //Get the entity.
            List<Site> sites = siteRepository.GetAll();

            //Map to DTO.
            Mapper.Reset();
            Mapper.CreateMap<Site, SiteDto>();
            Mapper.CreateMap<Client, ClientDto>()
                .ForMember(prop => prop.Sites, opt => opt.Ignore())
                .ForMember(prop => prop.Contacts, opt => opt.Ignore());
            List<SiteDto> siteDtos = Mapper.Map<List<Site>, List<SiteDto>>(sites);

            //Return DTO in a response object.
            return new GetResponse<List<SiteDto>>(siteDtos);
        }

        public Response CreateSite(CreateSiteRequest request)
        {
            //Load required repositories.
            IClientRepository clientRepository = ObjectFactory.GetInstance<IClientRepository>();
            ISiteRepository siteRepository = ObjectFactory.GetInstance<ISiteRepository>();

            //Create the parameter object from the request object, mapping any primitive types.
            Mapper.Reset();
            Mapper.CreateMap<CreateSiteRequest, CreateSiteParameters>()
                .ForMember(prop => prop.Client, opt => opt.Ignore());
            CreateSiteParameters parameters = Mapper.Map<CreateSiteRequest, CreateSiteParameters>(request);

            //Set the parameters with any required entities. Entities are 'Loaded', not 'Got' so only a proxy is returned with the Id. 
            //This way, it does not need to hit the database.
            parameters.Client = clientRepository.LoadById(request.ClientId);

            //Create the entity.
            Site site = Site.Create(parameters);

            //Validate the entity, and return ValidationErrorResponse if fails.
            ValidationMessageCollection messages = site.Validate();
            if (messages.Count > 0) return new ValidationErrorResponse(messages);

            //Save the entity.
            using (ITransactionProvider transactionProvider = ObjectFactory.GetInstance<ITransactionProvider>())
            {
                transactionProvider.BeginTransaction();
                siteRepository.Save(site);
                transactionProvider.CommitTransaction();
            }

            //Return a successful response (will only get here if no exception is received).
            return new CreateResponse(site.Id.Value);
        }

        public Response EditSite(EditSiteRequest request)
        {
            //Load required repositories.
            ISiteRepository siteRepository = ObjectFactory.GetInstance<ISiteRepository>();

            //Create the parameter object from the request object, mapping any primitive types.
            Mapper.Reset();
            Mapper.CreateMap<EditSiteRequest, EditSiteParameters>();
            EditSiteParameters parameters = Mapper.Map<EditSiteRequest, EditSiteParameters>(request);

            //Get the entity.
            Site site = siteRepository.GetById(request.SiteId);

            //Edit the entity.
            site.Edit(parameters);

            //Validate the entity, and return ValidationErrorResponse if fails.
            ValidationMessageCollection messages = site.Validate();
            if (messages.Count > 0) return new ValidationErrorResponse(messages);

            //Save the entity.
            using (ITransactionProvider transactionProvider = ObjectFactory.GetInstance<ITransactionProvider>())
            {
                transactionProvider.BeginTransaction();
                siteRepository.SaveOrUpdate(site);
                transactionProvider.CommitTransaction();
            }
            
            //Return a successful response (will only get here if no exception is received).
            return new Response(ResponseStatus.Success);
        }
    }
}
